package com.lenovo.nova.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListAdapter;
import android.widget.ListView;

import com.lenovo.nova.util.Applications;
import com.lenovo.nova.util.Applications.OnInputModeChangeListener;
import com.lenovo.nova.util.Applications.OnTouchBoardTouchedListener;
import com.lenovo.nova.util.Constant.Debug;
import com.lenovo.nova.util.debug.MyOldLog;
import com.lenovo.nova.util.debug.slog;
import com.lenovo.nova.util.view.KeyUtil;
import com.lenovo.nova.widget.windowmanager.WindowManagerArrow;

@SuppressLint("NewApi")
public class CustomArrowListView extends ListView implements OnTouchBoardTouchedListener, OnScrollListener, OnInputModeChangeListener {

	private int mItemIndex;
	private int mSmoothIndex;
	private int onHoverIndex;
	
	private Rect mOnHoverRect = new Rect();
	
	//如果需要setselection的时候，如果没有onLayout ,需要使用setSlectoinFromTop（index ，0）
//	protected int mItemAndDivideHeight = 99;
	protected int mItemAndDivideHeight = 0;
	
	private int mOnePageshowItemCount;
	
	public static final int ARROW_DOWN = 0;
	public static final int ARROW_UP = 1;
	
	private static final String TAG = "CustomListView";
//	private static int ARROW_OFFSET = 15;
	private static int ARROW_OFFSET_FOR_GLOABLE = 0;
	private static int ARROW_OFFSET_FOR_NEW_GUI = 25;
	private int mChildViewWith = 0;
	private boolean initialized = false;

	private int mTopArrowOffSet;
	private int mBottomArrowOffSet;

	private int mItemCount;
	
	private Drawable mHoverDrawable;
	
	public CustomArrowListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initLayout();
	}

	public CustomArrowListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initLayout();
	}

	public CustomArrowListView(Context context) {
		super(context);
		initLayout();
	}

	void initLayout() {
		//增加该接口监听，检测onScroll函数，以便于滚动的时候初始化 mSmoothIndex
		setOnScrollListener(this);
		setTopArrowOffSet(ARROW_OFFSET_FOR_NEW_GUI);
		setBottomArrowOffSet(-ARROW_OFFSET_FOR_NEW_GUI);
//		mHoverDrawable = mContext.getResources().getDrawable(R.drawable.blue_right_item_btn_pressed);
	}

	
	public void setHoverDrawable(Drawable draw){
		mHoverDrawable = draw;
	}
	
	public void setTopArrowOffSet(int offSet){
		mTopArrowOffSet = offSet;
	}
	public void setBottomArrowOffSet(int offSet){
		mBottomArrowOffSet = offSet;
	}
	
	@Override
	public void onGlobalLayout() {
		super.onGlobalLayout();
		slog.p(TAG,"onGlobalLayout initialized " + initialized );
		//onGlobalLayout be called many times, but initArrow just be call once 
		initArrow();
		refreshArrow();
	}

	private boolean isNeedShowArrow(){
		// height of all the item
		int mTotalChildHeight = calcTotalChildHeight();
		return ((mTotalChildHeight + getPaddingTop() + getPaddingBottom()) > getHeight());
	}
	
	private void refreshArrow() {
		
		int totalChildHeight = calcTotalChildHeight();
		int contentHeight = totalChildHeight + getPaddingTop() + getPaddingBottom();
		slog.p(TAG, "refreshArrow contentHeight is " + contentHeight );
		if (getHeight() > 0 && contentHeight > 0 && getWindowVisibility() == View.VISIBLE) {
			//when the children height is less than the parent height,
			// update the arrow(set all arrows invisiable)
			Rect outRect = new Rect();
			getDrawingRect(outRect);
			slog.p(TAG, "refreshArrow outRect " + outRect);
			boolean mCanFling = isNeedShowArrow();
			slog.p(TAG, "refreshArrow  mCanFling " + mCanFling + "  isFirstvisiableShow() " + isFirstvisiableShow() +
					"  mSmoothIndex " + mSmoothIndex + "  isLastVisiableShow() " + isLastVisiableShow());
			
			if(mCanFling && arrow != null){
				if(isFirstvisiableShow() && mSmoothIndex == 0){
					setShowBottomArrow();
				}else if(isLastVisiableShow()){
					setShowTopArrow();
				} else {
					setTwoArrowVisiable(true);
				}
			}else{
				setTwoArrowVisiable(false);
			}
			
			//有时候ListView的高度需要跟随着变化，所以需要刷新箭头的额位置
			int[] location = new int[2];
			getLocationOnScreen(location);
			int [] locationInWind = new int[2];
			getLocationInWindow(locationInWind);;
			int topY = location[1] - arrow.getTopImageViewHeight();
			slog.p(TAG,"init arrow location is " + location[0] + "   " + location[1] + " arrow topY is " + topY+
					"\n " + locationInWind[0] + "  " +locationInWind[1]
					);
			
			int height = getHeight();
			int topViewY = topY - ARROW_OFFSET_FOR_GLOABLE + mTopArrowOffSet;
			int bottomY = location[1] + height + ARROW_OFFSET_FOR_GLOABLE + mBottomArrowOffSet; 
			int imageX = location[0] + (getWidth() - arrow.getTopImageViewWidth()) / 2;
			
			arrow.showArrowYPosition(topViewY, bottomY);
			arrow.showArrowXPosition(imageX);
			slog.p(TAG,"topViewY " + topViewY +"  bottomY "+ bottomY + "  imageX  " +imageX);
			
		}
		
	}

	@Override
	public void setAdapter(ListAdapter adapter) {
		super.setAdapter(adapter);
		adapter.registerDataSetObserver(new DataSetObserver() {
			@Override
			public void onChanged() {
				slog.p(TAG, TAG + " registerDataSetObserver onChanged " + getChildCount() + "   " + getCount() );
			}
			@Override
			public void onInvalidated() {
				slog.p(TAG, TAG + " registerDataSetObserver onInvalidated " + getChildCount() + "   " + getCount() );
				setTwoArrowVisiable(false);
			}
		});
	}
	

	private int calcTotalChildHeight() {
		slog.p(TAG,"calcTotalChildHeight " + getCount() + "  " + getDividerHeight());
		try {
			slog.p(TAG,"calcTotalChildHeight getChildAt(0).getHeight() " +getChildAt(0).getHeight());
		} catch (Exception e) {
		}
		int mTotalChildHeight = 0;
		for (int i = 0; i < getCount(); i++) {
			if(getChildAt(0) != null){
				mTotalChildHeight += getChildAt(0).getHeight();
			}else{
				MyOldLog.e("null");
			}
		}
		//add divider height
		mTotalChildHeight += getDividerHeight() * (getCount() - 1);
		return mTotalChildHeight;
	}

	public void notifyNeedInitArrow(){
		initialized = false;
	}
	
	protected void setchildViewWith() {
		if (mChildViewWith != 0) {
			for (int i = 0; i < getChildCount(); i++) {
				View view = getChildAt(i);
				view.getLayoutParams().width = mChildViewWith;
			}
		}
	}



	public int getItemIndex() {
		return mItemIndex;
	}

	@Override
	public int getSelectedItemPosition() {
		return getItemIndex();
	}

	@Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		if (onCommonKey(keyCode, event)) {
			return true;
		}
		return super.onKeyUp(keyCode, event);
	}

	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if(keyCode == KeyEvent.KEYCODE_A) {
			Log.d("NovaSettings", "keycode : first" + getFirstVisiblePosition() + " end" + getLastVisiblePosition());
		}
		if(keyCode == KeyEvent.KEYCODE_C) {
			arrow(ARROW_UP);
		}
		if(keyCode == KeyEvent.KEYCODE_D) {
			arrow(ARROW_DOWN);
		}
		if(keyCode == KeyEvent.KEYCODE_B) {
			Log.d("NovaSettings", "keycode : first" + getFirstVisiblePosition() + " end" + getLastVisiblePosition());
			View firstView = this.getChildAt(0);
			Log.d("NovaSettings", " first re" + firstView.getY());
			
			printView(firstView,"first");
			View endView = this.getChildAt(getChildCount() - 1);
			printView(endView,"end");
			printView(this,"this");
//			arrow(ARROW_UP);
		}
		if (onCommonKey(keyCode, event)) {
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}
	
	private void printView(View view,Object  ... obj) {
		int[] location = new  int[2] ;
		view.getLocationOnScreen(location);
		Log.d("NovaSettings", "x:" + location[0] + " y:" + location[1] +"   "+ obj[0] + 
				" height:" + view.getHeight() + " padBo" + view.getPaddingBottom() + "  padTop" + view.getPaddingTop()
		+" mItemAndDivideHeight " + mItemAndDivideHeight		
		);
	}

	@Override
	public boolean onHoverEvent(MotionEvent event) {
		int x = (int) event.getX();
		int y = (int) event.getY();
		int position = pointToPosition(x, y);
		System.out.println("CustomListView onHoverEvent " + event.getAction() + " x , y " + x + " , " + y + " positioni " + position);
		
		switch(event.getAction()){
		case MotionEvent.ACTION_HOVER_EXIT:
			mOnHoverRect.setEmpty();
			invalidate();
			break;
		default:
			if (position != -1) {
				onHoverIndex = position;
				refreshOnHoverRect(onHoverIndex);
			} else {
			}
			
			break;
		}
		

		return super.onHoverEvent(event);
	}

	private void refreshOnHoverRect(int position) {
		if(position != -1){
			View firView = getChildAt(0);
			if(firView != null){
				firView.getDrawingRect(mOnHoverRect);
				int top = firView.getTop() + (firView.getHeight() + getDividerHeight()) * (onHoverIndex - getFirstVisiblePosition());
				mOnHoverRect.set(mOnHoverRect.left, 
						top,
						mOnHoverRect.right, 
						top + firView.getHeight());
			}else{
				slog.p("onHoverEvent","set mOnHoverRect enpty " + position + " " +onHoverIndex);
			}
			
			invalidate(mOnHoverRect);
		}
	}

	
	@Override
	protected void onScrollChanged(int l, int t, int oldl, int oldt) {
		super.onScrollChanged(l, t, oldl, oldt);
		slog.p(TAG, "onScrollChanged");
		initArrow();
		refreshArrow();
		refreshOnHoverRect(onHoverIndex);
	}
	
	private boolean isLastVisiableShow() {
		int lastVisiablePosition = getLastVisiblePosition(); 
		return lastVisiablePosition >= getCount() - 1;
	}

	private boolean isFirstvisiableShow() {
		View firstChild = this.getChildAt(0);
		if(firstChild != null &&  (getFirstVisiblePosition() == 0)) {
			if(firstChild.getY() + firstChild.getHeight() - firstChild.getPaddingBottom()  <= 0) {
				return false;
			}
		}
		return getFirstVisiblePosition() == 0 ;
	}

	
	
	public void arrow(int direction) {
		switch (direction) {
		case ARROW_DOWN:
			nextSmoothScroll();
			break;
		case ARROW_UP:
			lastSmoothScroll();
			break;
		default:
			break;
		}
	}

	@Override
	protected void onAttachedToWindow() {
		super.onAttachedToWindow();
		
		MyOldLog.p(Debug.METHOD_TAG,"onAttachedToWindow");
		SettingsApplication.get().addOnTochBoardTouchedListener(this);
		SettingsApplication.get().addOnInputModeChangeListener(this);
		getViewTreeObserver().addOnGlobalLayoutListener(this);
		
		arrow = new WindowManagerArrow(getContext(),false) {
			public void onClick(View v) {
				if (v == mTopView) {
					arrow(ARROW_UP);
				} else if (v == mBottomView) {
					arrow(ARROW_DOWN);
				}
			}
		};

		if(getAdapter()!=null && getAdapter().getCount() <= 1){
			setTwoArrowVisiable(false);
		}
	}

	@SuppressLint("NewApi")
	@Override
	protected void onDetachedFromWindow() {
		MyOldLog.p(Debug.METHOD_TAG,"onDetachedFromWindow");
		arrow.close();
		initialized = false;
		getViewTreeObserver().removeOnGlobalLayoutListener(this);
		SettingsApplication.get().removeOnInputChangeListener(this);
		SettingsApplication.get().removeOnTouchBoardListener(this);
		super.onDetachedFromWindow();
	}

	public void closeArrow() {
		if(arrow != null){
			arrow.close();
		}
		initialized = false;
	}

	@Override
	public void onHoverChanged(boolean hovered) {
		super.onHoverChanged(hovered);
	}

	public boolean onCommonKey(int keyCode, KeyEvent event) {
		if (event.getAction() == KeyEvent.ACTION_DOWN) {
			mItemCount = getCount();
			if (KeyUtil.isDown(keyCode) || KeyUtil.isUp(keyCode)) {
				switch (keyCode) {
				case KeyEvent.KEYCODE_DPAD_DOWN:
					if (mItemIndex < mItemCount - 1) {
						mItemIndex++;
					} else {
						return super.onKeyDown(keyCode, event);
					}
					break;
				case KeyEvent.KEYCODE_DPAD_UP:
					if (mItemIndex > 0) {
						mItemIndex--;
					} else {
						return super.onKeyDown(keyCode, event);
					}
					break;
				}
				setSelection(mItemIndex);
				return true;
			}
		}
		return false;
	}

	public void setDimension(int width, int height) {
		ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) getLayoutParams();
		if (width >= 0) {
			params.width = width;
		}
		if (height >= 0) {
			params.height = height;
		}
		setLayoutParams(params);
	}

	@Override
	public void setSelection(int position) {
		if (mOnePageshowItemCount <= 0) {
			//call super before onLayout be called
			super.setSelection(position);
		}else{
			//果需要setselection的时候，如果没有onLayout ,需要使用setSlectoinFromTop（index ，0）
			// we can get itmeFromTopDistance only after onLayout
			int itmeFromTopDistance = mItemAndDivideHeight * (position % mOnePageshowItemCount);
			setSelectionFromTop(position, itmeFromTopDistance);
			mItemIndex = position;
		}
	}

	public void nextSmoothScroll() {
		int index = mSmoothIndex;
		index += mOnePageshowItemCount;
		Log.d("shiqc1", "nextSmoothScroll....." + mSmoothIndex + "  index :" +index );
		if ((getAdapter()!=null)&&(index > getAdapter().getCount() - 1)) {
			// smoothScrollToPosition(index);
			index = getAdapter().getCount() - 1;
		}
		mSmoothIndex = index;
		smoothScrollToPositionFromTop(index, 0);
		slog.p("nextSmoothScroll index " + index);
	}
	
	public void lastSmoothScroll() {
		int index = mSmoothIndex;
		index -= mOnePageshowItemCount;
		if (index < 0) {
			index = 0;
		}
		// smoothScrollToPosition(index);
		smoothScrollToPositionFromTop(index, 0);
		mSmoothIndex = index;

		slog.d("CustomListView lastSmoothScroll " + index);
	}

	WindowManagerArrow arrow = null;
	private Rect outRect;

	public WindowManagerArrow getSuspendedArrow() {
		return arrow;
	}

	/**
	 * 该方法被调用一次就可以了，只是初始化上下箭头
	 */
	private void initArrow( ) {
		if (arrow != null && !initialized) {
			int childTotalHeightAndPadding = calcTotalChildHeight() + getPaddingBottom() + getPaddingTop();
			initialized = true;
			boolean mCanFling = isNeedShowArrow();
			slog.p(TAG,"initArrow  childTotalHeightAndPadding: " + childTotalHeightAndPadding + " mCanFling is " + mCanFling);
			if (mCanFling  && getWindowVisibility() == View.VISIBLE) {
				setShowBottomArrow();
			} else {
				setTwoArrowVisiable(false);
			}
			
		
		}else{
			if(arrow == null){
				MyOldLog.e("Error maybe arrow is null ");	
			}
		}
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		int mViewHeight = b - t;
		if(getChildAt(0)!=null){
			mItemAndDivideHeight = getChildAt(0).getHeight() + getDividerHeight(); 
			slog.p(TAG,"onLayout mItemAndDivideHeight is " + mItemAndDivideHeight);
		}
		
		if (mItemAndDivideHeight != 0 && mViewHeight % mItemAndDivideHeight == 0) {
			mOnePageshowItemCount = (mViewHeight / mItemAndDivideHeight);
		} else {
			if(mItemAndDivideHeight != 0 ){
				mOnePageshowItemCount = (mViewHeight / mItemAndDivideHeight) + 1;
			}
		}
	}

	
	
	private void executeHover(ViewGroup currentView) {
		if (currentView != null) {
			for (int i = 0; i < getChildCount(); i++) {
				ViewGroup view = (ViewGroup) getChildAt(i);
				if (view.getBackground() == null) {
					if (view.getChildCount() == 1 && view.getChildAt(0).getBackground() != null) {
						view = (ViewGroup) view.getChildAt(0);
					}
				}

				if (view.equals(currentView)) {
					view.setHovered(true);
				} else {
					view.setHovered(false);
				}
			}
		}
	}



	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		slog.d(TAG,"onScrollStateChanged scrollState " + scrollState);
	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
		slog.p(TAG,"onScroll firstVisibleItem " + firstVisibleItem + "  visibleItemCount " + visibleItemCount + "  totalItemCount" + totalItemCount);
		mSmoothIndex = firstVisibleItem;
	}

	@Override
	public void onTouchBoardTouched(KeyEvent event) {
		if (event.getAction() == KeyEvent.ACTION_UP) {
			if (KeyUtil.isTouchBoardUp(event.getKeyCode())) {
				nextSmoothScroll();
			}
			if (KeyUtil.isTouchBoardDown(event.getKeyCode())) {
				lastSmoothScroll();
			}
		}
	}

	@Override
	public void onInputModeChange(boolean isInTouchMode) {
		if (!isInTouchMode) {
			setSelector(mHoverDrawable);
			setSelection(onHoverIndex);
		}else{
			setSelector(getResources().getDrawable(android.R.color.transparent));
		}
		invalidate();
	}

	private void setShowTopArrow() {
		if(arrow!=null){
			arrow.setTopVisible(true);
			arrow.setBottomVisible(false);
		}else{
			MyOldLog.e("arrow is null");
		}
		if(Applications.isInDebugMode){
			MyOldLog.p("setShowTopArrow" , MyOldLog.RANGE_LAST_METHOD);
		}
	}
	
	private void setTwoArrowVisiable(boolean visiable) {
		if(arrow!=null){
			arrow.setTopVisible(visiable);
			arrow.setBottomVisible(visiable);
		}else{
			MyOldLog.e("arrow is null");
		}
		MyOldLog.p("setTwoArrowVisiable" , MyOldLog.RANGE_LAST_METHOD);
	}

	private void setShowBottomArrow() {
		if(arrow!=null){
			arrow.setTopVisible(false);
			arrow.setBottomVisible(true);
		}else{
			MyOldLog.e("arrow is null");
		}
		MyOldLog.p("setShowBottomArrow" ,  MyOldLog.RANGE_LAST_METHOD);
	}	
	
	@Override
	protected void dispatchDraw(Canvas canvas) {
		super.dispatchDraw(canvas);
		System.out.println("CustomListView dispatchDraw");
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		System.out.println("CustomListView onDraw");
		if(mHoverDrawable != null && SettingsApplication.get().isInTouchMode()){
			System.out.println(mOnHoverRect);
			mHoverDrawable.setBounds(mOnHoverRect);
			mHoverDrawable.draw(canvas);
		}
		
		super.onDraw(canvas);
	}

}
